#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
"""
@File    :   SSH.py
@Time    :   2024-07-23 09:56
@Author  :   坐公交也用券
@Version :   1.0
@Contact :   faith01238@hotmail.com
@Homepage : https://liumou.site
@Desc    :   当前文件作用
"""
import logging
import os
import subprocess
import sys
import time
from argparse import ArgumentParser
from datetime import datetime
from shutil import copy2
from sys import exit
import platform

# 创建一个自定义的日志记录器
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)

# 创建一个自定义的日志处理器，设置其输出格式
formatter = logging.Formatter('%(asctime)s [%(levelname)s] %(filename)s:%(lineno)d | %(funcName)s | %(message)s')
handler = logging.StreamHandler(sys.stdout)
handler.setFormatter(formatter)
logger.addHandler(handler)


def check_dependencies():
    """
    检查编译OpenSSH所需的依赖是否安装
    :return: True表示依赖齐全，False表示有缺失依赖
    """
    logger.info("开始检查编译依赖...")
    
    # 基础依赖检查
    dependencies = {
        # 编译工具
        "gcc": "C编译器",
        "make": "构建工具",
        "autoconf": "自动配置工具",
        # 系统工具
        "tar": "压缩包解压工具",
        "wget": "文件下载工具",
        # 开发库
        "zlib": "压缩库开发文件",
        "openssl": "加密库开发文件"
    }
    
    missing_deps = []
    
    # 检查系统类型
    system_type = platform.system().lower()
    distro = ""
    
    # 检测Linux发行版
    if system_type == "linux":
        try:
            with open("/etc/os-release", "r") as f:
                for line in f:
                    if line.startswith("ID=") or line.startswith("ID_LIKE="):
                        distro = line.split("=")[1].strip().strip('"')
                        break
        except:
            pass
    
    # 检查基本工具
    for tool, description in dependencies.items():
        if tool in ["zlib", "openssl"]:
            # 检查开发库
            if system_type == "linux":
                if "ubuntu" in distro or "debian" in distro:
                    # 检查Ubuntu/Debian的包
                    if tool == "zlib":
                        pkg_name = "zlib1g-dev"
                    elif tool == "openssl":
                        pkg_name = "libssl-dev"
                    else:
                        pkg_name = f"lib{tool}-dev"
                    
                    result = subprocess.run(["dpkg", "-l", pkg_name], 
                                          capture_output=True, text=True)
                    if result.returncode != 0:
                        missing_deps.append(f"{pkg_name} ({description})")
                elif "centos" in distro or "redhat" in distro or "fedora" in distro:
                    # 检查CentOS/RHEL的包
                    result = subprocess.run(["rpm", "-q", f"{tool}-devel"], 
                                          capture_output=True, text=True)
                    if result.returncode != 0:
                        missing_deps.append(f"{tool}-devel ({description})")
            else:
                # 其他系统，尝试通用检查
                result = subprocess.run(["which", tool], capture_output=True)
                if result.returncode != 0:
                    missing_deps.append(f"{tool} ({description})")
        else:
            # 检查普通工具
            result = subprocess.run(["which", tool], capture_output=True)
            if result.returncode != 0:
                missing_deps.append(f"{tool} ({description})")
    
    if missing_deps:
        logger.error("发现缺失的依赖项:")
        for dep in missing_deps:
            logger.error(f"  - {dep}")
        
        # 提供安装建议
        logger.info("\n安装建议:")
        if "ubuntu" in distro or "debian" in distro:
            logger.info("Ubuntu/Debian系统请执行:")
            logger.info("  apt update && apt install -y libssl-dev make zlib1g zlib1g-dev clang libssl-dev")
        elif "centos" in distro or "redhat" in distro:
            logger.info("CentOS/RHEL系统请执行:")
            logger.info("  yum clean all && yum makecache && yum install -y gcc gcc-c++ make zlib zlib-devel clang openssl openssl-devel")
        elif "fedora" in distro:
            logger.info("Fedora系统请执行:")
            logger.info("  dnf install -y gcc gcc-c++ make zlib zlib-devel clang openssl openssl-devel")
        else:
            logger.info("请根据您的系统包管理器安装上述缺失的依赖项")
        
        logger.warning("\n依赖检查失败，编译可能会失败！")
        return False
    else:
        logger.info("✓ 所有编译依赖检查通过")
        return True


def install_dependencies():
    """
    自动安装缺失的依赖（需要root权限）
    :return: True表示安装成功，False表示安装失败或无需安装
    """
    logger.info("开始检查并自动安装依赖...")
    
    # 检查root权限
    if os.geteuid() != 0:
        logger.error("自动安装依赖需要root权限，请使用sudo运行脚本")
        return False
    
    # 先检查是否所有依赖都已安装
    if check_dependencies():
        logger.info("✓ 所有依赖已安装，无需重复安装")
        return True
    
    # 检查系统类型
    system_type = platform.system().lower()
    distro = ""
    
    # 检测Linux发行版
    if system_type == "linux":
        try:
            with open("/etc/os-release", "r") as f:
                for line in f:
                    if line.startswith("ID=") or line.startswith("ID_LIKE="):
                        distro = line.split("=")[1].strip().strip('"')
                        break
        except:
            pass
    
    # 根据系统类型确定安装命令
    install_cmd = ""
    if "ubuntu" in distro or "debian" in distro:
        install_cmd = "apt update && apt install -y libssl-dev make zlib1g zlib1g-dev clang libssl-dev"
    elif "centos" in distro or "redhat" in distro:
        install_cmd = "yum clean all && yum makecache && yum install -y gcc gcc-c++ make zlib zlib-devel clang openssl openssl-devel"
    elif "fedora" in distro:
        install_cmd = "dnf install -y gcc gcc-c++ make zlib zlib-devel clang openssl openssl-devel"
    else:
        logger.error("无法自动识别系统类型，请手动安装依赖")
        return False
    
    logger.info(f"执行安装命令: {install_cmd}")
    result = os.system(install_cmd)
    
    if result == 0:
        # 安装完成后再次检查依赖是否齐全
        if check_dependencies():
            logger.info("✓ 依赖安装成功，所有依赖检查通过")
            return True
        else:
            logger.warning("⚠ 依赖安装完成，但仍有部分依赖缺失，请手动检查")
            return False
    else:
        logger.error("✗ 依赖安装失败，请手动安装")
        return False


def service(p: str):
	"""
	创建Service
	:param p:
	:return:
	"""
	os.system("mkdir -p /usr/lib/systemd/system_bak/")
	os.system("cp -rf /usr/lib/systemd/system/ssh*.service /usr/lib/systemd/system_bak/")
	os.system('rm -f /usr/lib/systemd/system/ssh*.service')
	
	# 彻底删除SysV init脚本和相关配置
	if os.path.exists("/etc/init.d/sshd"):
		os.system('rm -f /etc/init.d/sshd')
	if os.path.exists("/etc/init.d/ssh"):
		os.system('rm -f /etc/init.d/ssh')
	
	# 禁用systemd的SysV兼容服务
	os.system("systemctl disable ssh.service 2>/dev/null || true")
	os.system("systemctl mask ssh.service 2>/dev/null || true")
	
	f = '/usr/lib/systemd/system/sshd.service'
	txt = f"""[Unit]
Description=OpenSSH server daemon
Documentation=man:sshd(8) man:sshd_config(5)
After=network.target auditd.service
ConditionPathExists=!/etc/ssh/sshd_not_to_be_run

[Service]
EnvironmentFile=-/etc/default/ssh
ExecStart={p} -D $SSHD_OPTS
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartPreventExitStatus=255
Type=notify
RuntimeDirectory=sshd
RuntimeDirectoryMode=0755

[Install]
WantedBy=multi-user.target
Alias=sshd.service
"""
	try:
		with open(f, 'w', encoding="utf-8") as fp:
			fp.write(txt)
	except Exception as e:
		logger.error(e)
		return
	
	# 设置正确的文件权限
	os.system(f"chmod 644 {f}")
	
	os.system(f"systemctl daemon-reload")
	os.system(f"systemctl enable sshd.service")
	os.system(f"systemctl restart sshd.service")
	os.system(f"systemctl status sshd.service")


def create_service():
	"""

	:return:
	"""
	p = os.path.join(dst_arg, "sbin/sshd")
	if not os.path.isfile(p):
		logger.error(f"未找到openssh,请使用-s参数指定openssh安装目录: {p}")
		return
	logger.info("将仅生成Service文件,如需重新编译请先删除")
	service(p=p)
	exit(0)


class Upgrade:
	def __init__(self, dst: str, ssl: str, urls: dict, file: str, email: str, root_login: str , rebuild_ssh: bool):
		"""
		升级类
		:param dst: 设置安装目录
		:param email: 设置邮箱
		:param urls: 设置升级包地址
		:param file: 设置本地升级包
		:param ssl: 设置OPENSSL 安装目录
		:param root_login: 设置是否开启root远程登录(yes/no)
		:param rebuild_ssh: 设置是否重建.ssh目录
		"""
		self.email = email
		self.dst = dst
		self.ssl = ssl
		self.urls = urls
		self.file = file
		self.root_login = root_login
		self.rebuild_ssh = rebuild_ssh
		logger.debug(str(file).replace(".tar.gz", ''))
		self.tmp_dir = os.path.join(os.getcwd(), str(file).replace(".tar.gz", ''))
		self.url = urls
		self.filename = file
		self.failed = False
		self.dst_bin = os.path.join(self.dst, "bin")
		self.dst_sbin = os.path.join(self.dst, "sbin")
		self.ssh_dst_etc = os.path.join(self.dst, "etc")
		self.ssl_use = False
		self.sshd_new = os.path.join(self.dst_sbin, "sshd")

	def check(self):
		"""
		检测参数和编译依赖
		:return:
		"""
		# 先检查编译依赖
		if not check_dependencies():
			logger.warning("编译依赖检查失败，是否继续编译？(y/n): ")
			choice = input().strip().lower()
			if choice != 'y' and choice != 'yes':
				logger.info("用户选择中止编译")
				return False
			else:
				logger.warning("用户选择继续编译，可能会因依赖缺失导致编译失败")
		
		# 检查SSL参数（可选）
		if self.ssl is not None:
			if not os.path.exists(self.ssl):
				logger.error(f"指定的openssl目录不存在: {self.ssl}")
				exit(5)
			if not os.path.isdir(self.ssl):
				logger.error(f"指定的openssl路径不是目录: {self.ssl}")
				exit(6)
			self.ssl_use = True
		else:
			logger.info("本次安装未指定openssl,将使用系统默认的openssl")
			self.ssl_use = False
		
		return True

	def download(self):
		"""
		下载压缩包
		:return:
		"""
		# 如果文件已经存在则先删除
		if os.path.exists(self.filename):
			os.remove(self.filename)
		print("正在下载压缩包")
		# 开始下载并判断下载结果，如果下载失败则退出
		if os.system(f"wget {self.url}") != 0:
			print("下载失败")
			exit(1)

	def untar(self):
		"""
		解压压缩包
		:return:
		"""
		print("正在解压压缩包")
		# 根据文件扩展名选择解压命令
		if self.filename.endswith('.tar.gz') or self.filename.endswith('.tgz'):
			# 解压tar.gz文件
			c = f"tar -zxf {self.filename}"
		else:
			# 解压普通tar文件
			c = f"tar -xvf {self.filename}"
		
		# 执行解压命令
		if os.system(c) != 0:
			print("解压失败")
			exit(2)

	def compile(self):
		"""
		编译源码
		:return:
		"""
		if not os.path.isdir(self.tmp_dir):
			print(f"找不到解压目录: {self.tmp_dir}")
			exit(4)
		print("正在编译源码")
		os.chdir(self.tmp_dir)
		c = f"./configure --prefix={self.dst} "
		if self.ssl_use:
			c += f" --with-ssl-dir={self.ssl}"
		if os.system(c) != 0:
			print(f"预编译配置失败: [ {c} ]")
			exit(3)
		if os.system(f"make") != 0:
			print("编译失败: [ make ]")
			exit(4)

	def install(self):
		"""
		安装
		:return:
		"""
		print("正在安装")
		os.chdir(self.tmp_dir)
		c = "make install"
		if os.system(c) != 0:
			print(f"安装失败: [ {c} ]")
			exit(5)

	def clean(self):
		"""
		清理
		:return:
		"""
		print("正在清理")
		if os.path.exists(self.tmp_dir):
			os.system(f"rm -rf {self.tmp_dir}")
		if os.path.exists(self.filename):
			os.system(f"rm -f {self.filename}")

	def link_ssh_conf(self):
		"""
		链接sshd_config文件
		:return:
		"""
		dst = "/etc/ssh"
		# 获取当前时间,格式如下： 202405201230
		formatted_datetime = datetime.now().strftime('%Y%m%d%H%M%S')
		# 拼接文件名
		conf_new = f"{dst}_{formatted_datetime}"
		# 开始备份
		if os.path.exists(dst):
			c = f"mv {dst} {conf_new}"
			if os.system(c) == 0:
				logger.info(f"备份成功: [ {c} ]")
			else:
				logger.error(f"备份失败: [ {c} ]")
				exit(1)

		os.symlink(self.ssh_dst_etc, dst)

	def open_root(self):
		"""
		控制root登录设置
		:return:
		"""
		# 拼接源路径
		sshd_config = os.path.join(self.dst, "etc/sshd_config")
		if not os.path.exists(sshd_config):
			logger.error(f"配置文件不存在: [ {sshd_config} ]")
			exit(2)
		
		# 检查原配置中的PermitRootLogin设置
		current_root_login = None
		try:
			with open(sshd_config, 'r') as f:
				for line in f:
					line = line.strip()
					if line.startswith('PermitRootLogin'):
						parts = line.split()
						if len(parts) >= 2:
							current_root_login = parts[1].lower()
							break
		except Exception as e:
			logger.error(f"读取配置文件失败: {e}")
			exit(2)
		
		# 使用传入的参数值作为最终设置
		final_root_login = self.root_login
		logger.info(f"设置root登录为: {final_root_login}")
		
		# 应用配置
		if current_root_login is None:
			# 如果不存在则添加
			c = f"sed -i '$aPermitRootLogin {final_root_login}' {sshd_config}"
			if os.system(c) != 0:
				logger.error(f"设置root登录失败[ {sshd_config} ]")
				exit(2)
			else:
				logger.info(f"添加root登录设置: {final_root_login} [ {sshd_config} ]")
		else:
			# 如果存在则替换
			c = f"sed -i 's/PermitRootLogin.*/PermitRootLogin {final_root_login}/g' {sshd_config}"
			if os.system(c) != 0:
				logger.error(f"设置root登录失败[ {sshd_config} ]")
				exit(2)
			else:
				logger.info(f"设置root登录为: {final_root_login} [ {sshd_config} ]")

	def link_ssh_bin(self):
		"""
		连接
		:return:
		"""
		# 先获取当前安装的可执行文件列表
		ssh_list = os.listdir(self.dst_bin)
		for file in ssh_list:
			# 获取当前系统PATH目录中是否存在对应的链接文件
			r = subprocess.getstatusoutput(f"which {file}")
			if r[0] == 0:
				# 如果存在则删除
				os.system(f"rm -f {r[1]}")
			# 创建链接文件
			src = os.path.join(self.dst_bin, file)
			c = f"ln -s {src} /usr/bin/{file}"
			if os.system(c) == 0:
				print(f"创建链接文件成功: [ {c} ]")
			else:
				print(f"创建链接文件失败: [ {c} ]")
				self.failed = True
		# 替换sbin的sshd
		# 先获取旧的sshd
		sshd_old = subprocess.getoutput("which sshd")
		# 先删除旧的
		os.system(f"rm -f {sshd_old}")
		# 创建新的
		c = f"cp -rfi {self.sshd_new} /usr/sbin/sshd"
		if os.system(c) == 0:
			print(f"创建链接文件成功: [ {c} ]")
		else:
			print(f"创建链接文件失败: [ {c} ]")
			self.failed = True
		# 复制ssh-keygen
		os.system("rm -f /usr/bin/ssh-keygen")
		try:
			copy2(os.path.join(self.dst_bin, "ssh-keygen"), "/usr/bin/ssh-keygen")
			print("复制ssh-keygen成功")
		except Exception as e:
			print(f"复制ssh-keygen失败: [ {e} ]")
			self.failed = True

	def restart(self):
		"""
		重启
		:return:
		"""
		if self.failed:
			print("存在链接文件创建失败,请手动创建链接文件并重启服务")
			exit(8)
		print("正在重启服务验证")
		# 先重载配置
		if os.system("systemctl daemon-reload") != 0:
			print("服务重载失败")
			exit(7)
		if os.system("systemctl restart sshd") != 0:
			print("服务重启失败")
			exit(6)
		print("升级成功")

	def profile(self):
		"""
		写入profile文件
		:return:
		"""
		lib = os.path.join(self.dst, "lib")
		path_bin = os.path.join(self.dst, "bin")

		# 判断LD_LIBRARY_PATH变量是否存在 lib
		LD_LIBRARY_PATH_txt = False
		if "LD_LIBRARY_PATH" in os.environ:
			if lib not in os.environ["LD_LIBRARY_PATH"]:
				lib = f"{lib}:{os.environ['LD_LIBRARY_PATH']}"
				LD_LIBRARY_PATH_txt = True
		else:
			LD_LIBRARY_PATH_txt = True

		print("正在写入profile文件")
		try:
			with open(file="/etc/profile", mode="a+", encoding="utf-8") as f:
				# if write_path:
				# 	f.write(f"export PATH={path_bin}\n")
				if LD_LIBRARY_PATH_txt:
					f.write(f"export LD_LIBRARY_PATH={lib}\n")
		except Exception as e:
			print(f"写入profile文件失败:  {e}")
			exit(9)
		print("写入profile文件成功")
		# 开始加载新的配置
		os.system("source /etc/profile")
		os.environ["PATH"] = f"{path_bin}:{os.environ['PATH']}"
		os.environ["LD_LIBRARY_PATH"] = lib

	def reconstruction(self):
		"""
		重建.ssh
		:return:
		"""
		# 开始删除.ssh
		print("正在重建.ssh")
		# 通过HOME目录和.ssh拼接
		ssh_dir = os.path.join(os.environ["HOME"], ".ssh")
		os.system(f"rm -rf {ssh_dir}")
		# 开始执行密钥创建并设置预定义的邮箱
		if os.system(f"ssh-keygen -t rsa -b 4096 -C \"{self.email}\" -f {ssh_dir}/id_rsa -N \"\"") != 0:
			print("密钥创建失败")
			exit(10)
		print("重建.ssh成功")

	def start(self, download):
		"""

		:param download:
		:return:
		"""
		# 保存原始工作目录
		original_cwd = os.getcwd()
		
		# 检查依赖和参数，如果检查失败则退出
		if not self.check():
			logger.info("编译过程已中止")
			exit(0)
		
		if download:
			self.download()
		self.untar()
		self.compile()
		self.install()
		self.link_ssh_bin()
		self.link_ssh_conf()
		self.profile()
		# 根据参数决定是否重建.ssh
		if self.rebuild_ssh:
			self.reconstruction()
		# self.write_sshd()
		self.open_root()
		self.clean()
		
		# 清理完成后返回到原始工作目录
		os.chdir(original_cwd)
		
		# service("/usr/sbin/sshd")
		create_service()
		self.restart()



def check_current_root_login():
	"""
	检查当前系统的root登录配置状态
	:return: 返回默认的PermitRootLogin值字符串 ("yes" 或 "no")
	"""
	# 检查系统默认的SSH配置文件路径
	possible_sshd_configs = [
		"/etc/ssh/sshd_config",
		"/etc/sshd_config",
		"/usr/local/etc/sshd_config"
	]
	
	sshd_config_path = None
	for config_path in possible_sshd_configs:
		if os.path.exists(config_path):
			sshd_config_path = config_path
			break
	
	if sshd_config_path is None:
		logger.warning("未找到SSH配置文件，将使用默认值: yes")
		return "yes"
	
	try:
		with open(sshd_config_path, 'r') as f:
			for line in f:
				line = line.strip()
				# 跳过注释行
				if line.startswith('#'):
					continue
				# 查找PermitRootLogin配置
				if line.startswith('PermitRootLogin'):
					parts = line.split()
					if len(parts) >= 2:
						value = parts[1].lower()
						# 只有明确设置为no时才返回no
						if value == "no":
							logger.info(f"检测到当前系统root登录配置: {value} (来自 {sshd_config_path})")
							return "no"
						else:
							logger.info(f"检测到当前系统root登录配置: {value} (来自 {sshd_config_path})，将使用默认值: yes")
							return "yes"
		
		# 如果没有找到PermitRootLogin配置，则返回默认值"yes"
		logger.warning(f"配置文件中未找到PermitRootLogin设置 ({sshd_config_path})，将使用默认值: yes")
		return "yes"
	except Exception as e:
		logger.error(f"读取SSH配置文件失败: {e}，将使用默认值: yes")
		return "yes"


def use():
	"""
	使用免责声明
	:return:
	"""
	print("""
	免责声明:
	操作系统环境问题由使用者自行维护,此脚本只是个人编写，不代表任何平台或单位
	1. 本脚本仅供学习交流使用,请勿用于非法用途
	2. 脚本作者不对因使用本脚本而导致的任何问题或损失负责,请先自行阅读源码后再决定是否继续
	3. 可接受脚本bug反馈，但是不提供使用指导,请自行判断,不懂的地方可以通过-h参数获取帮助
	4. 如遇到代码问题可自行修改源码或者反馈，但是作者不会保障及时的修复
	5. 下班时间不会回复、处理任何此类脚本的问题
	""")
	while True:
		c = input("是否继续?(y/n): ")
		if c == "y":
			break
		elif c == "n":
			exit(0)
		else:
			print("输入错误,请重新输入")


def create_user():
	"""
	创建sshd用户
	:return:
	"""
	# 先判断是否已存在
	if subprocess.getstatusoutput("id sshd")[0] != 0:
		if os.system("useradd sshd") != 0:
			logger.error("用户创建失败")


if __name__ == "__main__":
	start_time = time.time()
	# 设置传参自定义URL
	url = 'https://mirrors.aliyun.com/openssh/portable/openssh-10.2p1.tar.gz'
	arg = ArgumentParser(description='当前脚本版本: 1.1_20251029164439', prog="OpenSshCompileInstall")
	h = f"在线模式: 自定义设置压缩包链接(当设置文件路径则忽略此参数),默认: {url}"
	arg.add_argument("-u", "--url", help=h, default=url, required=False)
	h = "离线模式: 手动指定压缩包路径,不从网页下载(默认使用网页下载)"
	arg.add_argument("-f", "--file", help=h, required=False)
	h = f"设置openssl的安装目录(如需指定openssl版本或系统无法识别则需要传入此参数),例如: /usr/local/openssl3.3.0"
	arg.add_argument("-ssl", "--ssl", help=h, required=False)
	# 设置程序安装目录自定义
	arg.add_argument("-d", "--dst", help=f"设置程序安装目录,默认: /usr/local/openssh", default="/usr/local/openssh")
	h = f"新版本安装后是否重建.ssh目录，默认不重建(如需重建请使用-s/--rebuild-ssh参数)"
	arg.add_argument("-e", "--email", help=h, default="liumou@qq.com")
	
	# 获取当前系统的root登录状态作为动态默认值
	current_root_login = check_current_root_login()
	
	# 设置是否开启root远程登录
	h = f"设置是否开启root远程登录(yes/no)，默认: {current_root_login} (当前系统配置)"
	arg.add_argument("-r", "--root-login", help=h, type=str, choices=["yes", "no"],
					default=current_root_login, required=False)
	
	# 设置是否重建.ssh目录
	arg.add_argument("-s", "--rebuild-ssh", help="设置是否重建.ssh目录，默认不重建", action="store_true")
	
	# 使用布尔值判断是否需要创建service
	arg.add_argument("-q", "--quit", help=f"创建service之后直接退出", action="store_true")
	url = arg.parse_args().url
	filename = arg.parse_args().file
	ssl_arg = arg.parse_args().ssl
	dst_arg = arg.parse_args().dst
	email_arg = arg.parse_args().email
	root_login_arg = arg.parse_args().root_login
	quit_arg = arg.parse_args().quit
	download_ = False
	if filename:
		filename = os.path.abspath(filename)
	else:
		filename = str(url.split("/")[-1])
		download_ = True
	if quit_arg:
		create_service()
		exit(0)

	use()
	logger.debug(f"参数: {arg.parse_args()}")
	create_user()
	os.system("mkdir -p /var/empty")
	upgrade = Upgrade(dst=dst_arg, ssl=ssl_arg, urls=url, file=filename, email=email_arg, root_login=root_login_arg, rebuild_ssh=arg.parse_args().rebuild_ssh)
	upgrade.start(download=download_)
	logger.info(f"升级完成->耗时: {time.time() - start_time}")
